package org.drushpal.service.connecter
{
	import flash.desktop.NativeProcess;
	import flash.desktop.NativeProcessStartupInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.NativeProcessExitEvent;
	import flash.events.ProgressEvent;
	import flash.filesystem.File;
	import flash.utils.ByteArray;
	
	import flashx.textLayout.formats.Float;
	
	import mx.managers.CursorManager;
	import mx.utils.ObjectUtil;
	import mx.utils.UIDUtil;
	
	import org.drushpal.model.vo.Connection;
	import org.drushpal.service.CloseConnectionEvent;
	import org.drushpal.service.DrushServiceEvent;
	
	public class Plink extends Connecter
	{
		
		public function Plink(onError:Function,onComplete:Function,disp:IEventDispatcher)
		{
			super(onError,onComplete,disp);
		}
		
		
		
		override public function connect(connection:Connection):void{
			process = new NativeProcess();
			uuid = UIDUtil.createUID();
			
			_startupInfo = new NativeProcessStartupInfo();
			_startupInfo.arguments = connectionArgs(connection);
			_startupInfo.executable = File.applicationDirectory.resolvePath("bin/plink.exe");
			
			process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA,onOutput);
			process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA,onProcessError);
			process.addEventListener(NativeProcessExitEvent.EXIT,onExit);
			process.start(_startupInfo);			
		}		
		
		//NEED to add flag if response will come through ERROR_DATA so we can do the complete stuff.
		override protected function execute(cmd:String,completeEvent:String):void{
			if(process.running){
				cmd+='; echo '+ uuid + '\n'
				process.standardInput.writeUTFBytes(cmd);
				_completeEvent = completeEvent;
			}			
		}
		public function onExit(e:NativeProcessExitEvent):void{
			trace(e.exitCode); //TODO: alert something went wrong if there are exit codes
			process.removeEventListener(NativeProcessExitEvent.EXIT,onExit);
			process.removeEventListener(ProgressEvent.STANDARD_ERROR_DATA,onProcessError);
			process.removeEventListener(ProgressEvent.STANDARD_OUTPUT_DATA,onOutput);
			dispatcher.dispatchEvent(new CloseConnectionEvent(CloseConnectionEvent.CLOSE));		
		}
		public function onOutput(e:ProgressEvent):void{ 
			var out:String = "";
			if(process.running){				
			 	out = process.standardOutput.readMultiByte(process.standardOutput.bytesAvailable,"utf-8");
				out = out.split("\r").join("");
				output+=out;			
				if(out.indexOf(uuid)>=0){
					complete();
				}else if(out.indexOf("(y/n)")>-1){
					_errorCallback.call(null,out,this);
				}
			}
		}
		
		/**
		 * Process error handling...
		 * Sometimes stuff that's not an error comes through here... why? i'm not sure... but complete gets called eventually anyway.
		 **/ 
		public function onProcessError(e:ProgressEvent):void{
			if(process.running)	error=process.standardError.readUTFBytes(process.standardError.bytesAvailable).split("\r").join("");
			_errorCallback.call(null,error,this);
		}
		
		/**
		 * depending on the connection properties, return appropriate connection vars
		 **/
		private function connectionArgs(connection:Connection):Vector.<String>{
			var args:Vector.<String> = new Vector.<String>();
			args.push("-ssh");
			args.push(connection.host);
			if(connection.port){
				args.push('-P');
				args.push(connection.port);
			}
			args.push("-T");
			args.push("-l");
			args.push(connection.username);
			if(connection.identity.length){
				args.push("-i");
				args.push(connection.identity);
			}
			if(connection.password.length){
				args.push("-pw");
				args.push(connection.password);
			}
			return args;
		}
	}
}